import numpy

from utils.numer_utils import math


class Slot:
    def __init__(self):
        self.value: numpy.int32 = None  # 基本数据类型 long/double 占用两个slot
        # heapObject
        self.ref = None  # 引用数据类型

    def getValue(self) -> numpy.int32:
        return self.value

    def getRef(self):
        return self.ref

    def setValue(self, value: numpy.int32):
        self.value = value

    def setRef(self, ref):
        self.ref = ref


class Slots:
    def __init__(self):
        self.slots = []

    def append(self, slot: Slot):
        self.slots.append(slot)

    def setInt(self, index: int, val: numpy.int32):
        self.slots[index].setValue(val)

    def setFloat(self, index: int, val: numpy.float32):
        self.setInt(index=index, val=math.float32_to_bits(val))

    def setLong(self, index: int, val: numpy.int64):
        self.slots[index].setValue(val & 0xFFFFFFFF)
        self.slots[index + 1].setValue((val >> 32) & 0xFFFFFFFF)

    def setDouble(self, index: int, val: numpy.float64):
        longValue = math.float64_to_bits(val)
        self.setLong(index, val=longValue)

    def getDouble(self, index: int) -> numpy.float64:
        longValue = self.getLong(index=index)
        return math.bit_to_float64(bits_64=longValue)

    def getLong(self, index: int) -> numpy.float64:
        low_part = self.slots[index].getValue()
        high_part = self.slots[index + 1].getValue()
        return (high_part << 32) | low_part

    def getInt(self, index: int) -> numpy.int32:
        return self.slots[index].getValue()

    def getFloat(self, index: int) -> numpy.float32:
        return math.bit_to_float32(self.getInt(index=index))

    def setRef(self, index: int, ref):
        self.slots[index].setRef(ref)

    def getRef(self, index: int):
        return self.slots[index].getRef()

    def makeSlot(self, maxLocals: int):
        if maxLocals > 0:
            for i in range(0, maxLocals):
                self.slots.append(Slot())
        return self

    def setSlot(self, index: int, slot: Slot):
        self.slots[index] = slot

    def getSlot(self, index: int) -> Slot:
        return self.slots[index]

    def clear(self):
        for slot in self.slots:
            if slot is not None:
                slot.setValue(None)
                slot.setRef(None)
